#include "CustomControl.h"

/*
 * 驱动状态是可查询的。
 * 中间服务，建立键盘输入与鼠标输入与gui相关的表。hwnd是关键字。
 * 这个服务从具体的设备中拉取数据。查询，匹配。转化为局部坐标、偏移坐标
 * 日常应用是无法访问到设备本身。
 * 强化一定的优先级。中介设备的优先级。
 * 
 */
const int g_nCaptionLen = 50;

COwnerDrawButton::COwnerDrawButton ( void ) : m_hWnd ( NULL ), m_hFourStateBitmap ( NULL ), \
	m_fTrackMouse ( FALSE )
{

}

COwnerDrawButton::~COwnerDrawButton ( void )
{
	if ( m_hFourStateBitmap ) {
		DeleteObject ( m_hFourStateBitmap );
	}
	if ( m_hFont ) {
		DeleteObject ( m_hFont );
	}
}

BOOL COwnerDrawButton::Create ( LPCSTR lpszCaption, const RECT& rect, HWND hParentWnd, \
                                UINT nID, LPCSTR lpszImage )
{
	if ( m_hWnd )
		return FALSE;

	m_hFourStateBitmap = ( HBITMAP ) LoadImage ( NULL, lpszImage, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
	if ( NULL == m_hFourStateBitmap ) {
		goto CREATE_FAIL;
	}

	m_hWnd = CreateWindow ( "BUTTON", lpszCaption, \
	                        WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_OWNERDRAW, \
	                        rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, \
	                        hParentWnd, ( HMENU ) nID, NULL, NULL );

	if ( NULL == m_hWnd ) {
		goto CREATE_FAIL;
	}

	m_OldProc = ( WNDPROC ) SetWindowLong ( m_hWnd, GWL_WNDPROC, ( LONG ) ButtonProc );
	SetWindowLong ( m_hWnd, GWL_USERDATA, ( LONG ) this );

	m_hFont = CreateFont ( 12, 0, 0, 0, FW_NORMAL, FALSE, FALSE, 0, ANSI_CHARSET, \
	                       OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, "Arial" );

	return TRUE;

CREATE_FAIL:
	if ( m_hFourStateBitmap ) {
		DeleteObject ( m_hFourStateBitmap );
	}
	return FALSE;
}

LRESULT CALLBACK COwnerDrawButton::ButtonProc ( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
	PAINTSTRUCT ps;
	HDC hdc;
	COwnerDrawButton *_this = ( COwnerDrawButton * ) GetWindowLong ( hWnd, GWL_USERDATA );
	_this->m_hWnd = hWnd;

	switch ( message ) {
	case WM_PAINT:
		hdc = BeginPaint ( hWnd, &ps );
		// TODO: Add any drawing code here...
		_this->Draw ( hdc );
		EndPaint ( hWnd, &ps );
		break;
	case WM_ERASEBKGND:
		return TRUE;
	case WM_DRAWITEM: {
		DRAWITEMSTRUCT *pDrawItemSturct = ( DRAWITEMSTRUCT * ) lParam;

		if ( pDrawItemSturct->itemState & ODS_FOCUS ) {
			RECT rtFocus = pDrawItemSturct->rcItem;
			rtFocus.left += 3;
			rtFocus.top += 3;
			rtFocus.right -= 3;
			rtFocus.bottom -= 3;
			_this->DrawFocusRect ( pDrawItemSturct->hDC, rtFocus );
		}
		//_this->Draw(pDrawItemSturct->hDC);
	}
	break;
	case WM_LBUTTONDOWN: {
		_this->OnLbuttonDown ( wParam, lParam );

	}
	break;
	case WM_LBUTTONUP: {
		_this->OnLbuttonUp ( wParam, lParam );

	}
	break;
	case WM_LBUTTONDBLCLK: {
		_this->OnLbuttonDBClick ( wParam, lParam );

	}
	break;
	case WM_MOUSEMOVE: {
		_this->OnMouseMove ( wParam, lParam );
	}
	break;
	case WM_MOUSELEAVE: {
		_this->OnMouseLeave ( wParam, lParam );
	}
	break;
	default:
		return CallWindowProc ( _this->m_OldProc, hWnd, message, wParam, lParam );
	}
	return 0;
}
void COwnerDrawButton::OnLbuttonDown ( WPARAM wParam, LPARAM lParam )
{
	SetCapture ( m_hWnd );
	m_nButtonState = STATE_DOWN;
	InvalidataCtrl();
}
void COwnerDrawButton::OnLbuttonUp ( WPARAM wParam, LPARAM lParam )
{
	if ( m_nButtonState == STATE_DOWN ) {
		ReleaseCapture();
		POINT pt = {};
		GetCursorPos ( &pt );
		RECT rcWnd = {};
		GetWindowRect ( m_hWnd, &rcWnd );
		if ( PtInRect ( &rcWnd, pt ) ) {
			m_fTrackMouse = TRUE;
			m_nButtonState = STATE_FOCUS;
			SendMessage ( GetParent ( m_hWnd ), WM_COMMAND, MAKEWPARAM ( GetDlgCtrlID ( m_hWnd ), \
			              BN_CLICKED ), ( LPARAM ) m_hWnd );
		} else {
			m_fTrackMouse = FALSE;
			m_nButtonState = STATE_UP;
		}
		InvalidataCtrl();
	}
}

void COwnerDrawButton::OnLbuttonDBClick ( WPARAM wParam, LPARAM lParam )
{
	SendMessage ( m_hWnd, WM_LBUTTONDOWN, NULL, NULL );
}

void COwnerDrawButton::OnMouseMove ( WPARAM wParam, LPARAM lParam )
{
	if ( !m_fTrackMouse ) {
		TRACKMOUSEEVENT MouseEvent = {sizeof ( TRACKMOUSEEVENT ) };
		MouseEvent.dwFlags = TME_LEAVE;
		MouseEvent.hwndTrack = m_hWnd;
		MouseEvent.dwHoverTime = 1000;
		TrackMouseEvent ( &MouseEvent );

		m_fTrackMouse = TRUE;
		m_nButtonState = STATE_FOCUS;
		InvalidataCtrl();
	}
}

void COwnerDrawButton::OnMouseLeave ( WPARAM wParam, LPARAM lParam )
{
	m_fTrackMouse = FALSE;
	m_nButtonState = STATE_UP;
	InvalidataCtrl();
}

void COwnerDrawButton::Draw ( HDC hDC )
{
	HDC hMemDC = CreateCompatibleDC ( hDC );
	HBITMAP hOldBmp = NULL;
	BITMAP bmpInfo = {};

	hOldBmp = ( HBITMAP ) SelectObject ( hMemDC, m_hFourStateBitmap );
	GetObject ( m_hFourStateBitmap, sizeof ( bmpInfo ), &bmpInfo );


	RECT rcWnd = {};
	GetClientRect ( m_hWnd, &rcWnd );
	int nWidth = rcWnd.right - rcWnd.left;
	int nHeight = rcWnd.bottom - rcWnd.top;
	int nBmpWidth = bmpInfo.bmWidth / 4;
	int nBmpHeight = bmpInfo.bmHeight;
	//绘制背景图
	SetStretchBltMode ( hDC, HALFTONE );
	StretchBlt ( hDC, 0, 0, nWidth, nHeight, hMemDC, nBmpWidth * m_nButtonState, \
	             0, nBmpWidth, nBmpHeight, SRCCOPY );

	if ( m_nButtonState == STATE_DOWN ) {
		rcWnd.top += 2;
	}

	//绘制文本
	char szCaption[g_nCaptionLen] = {};
	GetWindowText ( m_hWnd, szCaption, g_nCaptionLen - 1 );
	if ( strlen ( szCaption ) > 0 ) {
		SetBkMode ( hDC, TRANSPARENT );
		char *pReturnPos = NULL;
		HFONT hOldFont = ( HFONT ) SelectObject ( hDC, m_hFont );
		if ( pReturnPos = strstr ( szCaption, "\\r\\n" ) ) {
			//pReturnPos[0] = '\r';
			//pReturnPos[1] = '\n';
			//strcpy(&pReturnPos[2], &pReturnPos[4]);
			char *pszSecondLine = pReturnPos + 4;
			rcWnd.bottom = ( rcWnd.bottom + rcWnd.top ) / 2;
			rcWnd.top += 1;
			DrawText ( hDC, szCaption, pReturnPos -  szCaption, &rcWnd, DT_CENTER );
			rcWnd.top -= 1;
			rcWnd.bottom = rcWnd.bottom * 2 - rcWnd.top;
			rcWnd.top = ( rcWnd.bottom + rcWnd.top ) / 2;
			rcWnd.top -= 1;
			DrawText ( hDC, pszSecondLine, strlen ( pszSecondLine ), &rcWnd, DT_CENTER );
		} else {
			DrawText ( hDC, szCaption, strlen ( szCaption ), &rcWnd, DT_CENTER | DT_VCENTER | DT_SINGLELINE );
		}
		SelectObject ( hDC, hOldFont );
	}

	SelectObject ( hMemDC, hOldBmp );
	DeleteDC ( hMemDC );
}

void COwnerDrawButton::DrawFocusRect ( HDC hDC, RECT &rcWnd )
{
	HPEN hOldPen = NULL;
	HPEN hDrawPen = CreatePen ( PS_DOT, 2, RGB ( 0, 0, 0 ) );

	HBRUSH hBrush = ( HBRUSH ) GetStockObject ( NULL_BRUSH );
	HBRUSH hOldBrush = ( HBRUSH ) SelectObject ( hDC, hBrush );
	hOldPen = ( HPEN ) SelectObject ( hDC, hDrawPen );
	Rectangle ( hDC, rcWnd.left, rcWnd.top, rcWnd.right, rcWnd.bottom );

	SelectObject ( hDC, hOldBrush );
	SelectObject ( hDC, hOldPen );
	DeleteObject ( hDrawPen );
}

bool COwnerDrawButton::InvalidataCtrl()
{
	//RECT rcWnd = {};
	//GetClientRect(m_hWnd, &rcWnd);
	//InvalidateRect(m_hWnd, &rcWnd, bErase);
	HDC hDC = GetDC ( m_hWnd );
	Draw ( hDC );
	ReleaseDC ( m_hWnd, hDC );
	return true;
}

void COwnerDrawButton::EnableButton ( bool fEnable )
{
	if ( fEnable ) {
		m_nButtonState = STATE_UP;
	} else {
		m_nButtonState = STATE_DISABLE;
	}
	EnableWindow ( m_hWnd, fEnable );
	InvalidataCtrl();
}
